package com.globo.opensocial;

import java.util.Stack;
import java.util.StringTokenizer;

import com.globo.opensocial.tags.ForTag;

public class Parser {

    private Stack<String> variables;
    private Application app;

    public Parser(Application app) {
        this.app = app;
        variables = new Stack<String>();
    }

    /**
     * Before for.
     *
     * @param var
     * @param key
     */
    public void push(String var, String key) {
        variables.add(var);
        variables.add(key);
    }

    /**
     * Before for.
     *
     * @param forTag
     */
    public void push(ForTag forTag) {
        variables.add(forTag.getKey());
        variables.add(forTag.getVar());
    }

    /**
     * After For.
     */
    public void pop() {
        variables.pop();
        variables.pop();
    }

    public String getArrayToken(String name) {
        return processToken(name, "A");
    }

    public String getValueToken(String name) {
        return processToken(name, "V");
    }

    /**
     * Process a token.
     *
     * @param token
     * @param function
     * @return
     */
    private String processToken(String token, String function) {

        token = token.trim();
    	
        String object = token;
        String value = null;

        if (token.indexOf(".") != -1) {
            object = token.split("\\.")[0];
            value = token.split("\\.")[1];
        }

        if (variables.indexOf(object) != -1) {
            return token;
        } else {
            if (value != null) {
                return "this." + function + "(\"" + object + "\")."
                        + safeFunctionParams(value);
            } else {
                return "this." + function + "(\"" + object + "\")";
            }
        }
    }

    /**
     * Search a token in function params
     *
     * @param input
     * @return
     */
    public String safeFunctionParams(String input) {

        StringBuffer output = new StringBuffer();

        String t = "()., ";

        StringTokenizer st = new StringTokenizer(input, t, true);

        boolean inParam = false;

        while (st.hasMoreTokens()) {
            String token = st.nextToken();
            if (inParam) {
                if (token.equals(")")) {
                    inParam = false;
                }
                if (t.indexOf(token) != -1) {
                    output.append(token);
                } else {
                    output.append(getValueToken(token));
                }
            } else {
                if (token.equals("(")) {
                    inParam = true;
                }
                output.append(token);
            }
        }
        return output.toString();
    }

    /**
     * Handles logic to translate variables.
     *
     * @param input
     * @return
     */
    public String filterText(String input) {
        StringBuffer output = new StringBuffer();

        StringTokenizer st = new StringTokenizer(input, "{}", true);

        boolean inToken = false;

        while (st.hasMoreTokens()) {
            String token = st.nextToken();

            if (inToken) {
                if (token.equals("}")) {
                    inToken = false;
                } else {
                    output.append("\" + " + getValueToken(token) + " + \"");
                }
            } else {
                if (token.equals("{")) {
                    inToken = true;
                } else {
                    output.append( token.replaceAll("\n", "\\\\n")
                    					.replaceAll("\\\"", "\\\\\""));
                }
            }
        }
        return output.toString();
    }

    /**
     * Try gets the structure.
     *
     * @param nodeValue
     * @return
     */
    public String safeIf(String nodeValue) {

        if (nodeValue.equals("true") || nodeValue.equals("1")) {
            return nodeValue;
        }
        /*
           * if ( variables.indexOf(nodeValue) != 1 ) { return nodeValue; }
           */

        if (nodeValue.matches("[a-zA-Z_0-9]+")) {
            return getValueToken(nodeValue);
        }

        StringBuffer output = new StringBuffer();

        StringTokenizer st = new StringTokenizer(nodeValue, "{}", true);

        boolean inToken = false;

        while (st.hasMoreTokens()) {
            String token = st.nextToken();

            if (inToken) {
                if (token.equals("}")) {
                    inToken = false;
                } else {
                    output.append(" " + getValueToken(token) + " ");
                }
            } else {
                if (token.equals("{")) {
                    inToken = true;
                } else {
                    output.append(token);
                    // token.replaceAll("\n", "\\n").replaceAll( "\\\"",
                    // "\\\\\""));
                }
            }
        }
        return output.toString();
    }

    /**
     * Safe javascript function caller.
     *
     * @param input
     * @return
     * @TODO: Add safety code.
     */
    public String getSafeFunction(String input) {

        input = input.trim();

        if (input.startsWith("app.")) {

            StringBuffer out = new StringBuffer();
            out.append("function() {");
            out.append(safeIf(safeFunctionParams(input.replace("app.", app
                    .getId()
                    + "."))));
            // processar aqui.
            out.append(";};");
            return out.toString();

        } else {
            StringBuffer out = new StringBuffer();
            out.append("function() {");
			out.append(input);
			out.append(";};");
			return out.toString();
		}
	}

}
